package com.lktx.sso;

import cn.dev33.satoken.stp.StpUtil;
import cn.dev33.satoken.util.SaResult;
import cn.hserver.plugin.web.annotation.Controller;
import cn.hserver.plugin.web.annotation.RequestMapping;
import cn.hserver.plugin.web.interfaces.HttpRequest;
import cn.hserver.plugin.web.interfaces.HttpResponse;
import cn.hutool.json.JSONObject;
import cn.hutool.json.JSONUtil;
import com.ejlchina.okhttps.OkHttps;
import com.fasterxml.jackson.core.JsonProcessingException;

import java.util.HashMap;
import java.util.List;
import java.util.Map;


/**
 * Sa-OAuth2 Client端 控制器 
 * @author click33 
 */
@Controller
public class SaOAuthClientController {

	// 相关参数配置 
	private final String clientId = "d2cc07e819864dfbb9ff6cb143fc386e";								// 应用id
	private final String clientSecret = "a79fdf0e103148169bc83ff6c0ca6184";		// 应用秘钥
	private final static String serverUrl = "http://127.0.0.1:8888";	// 服务端接口

	// 进入首页 
	@RequestMapping("/")
	public void index(HttpRequest request, HttpResponse response) {
		Map<String, Object> data = new HashMap<>();
		Object loginIdDefaultNull = StpUtil.getLoginIdDefaultNull();
		data.put("uid", loginIdDefaultNull==null?"":loginIdDefaultNull);
		response.sendTemplate("index.ftl", data);
	}
	
	// 根据Code码进行登录，获取 Access-Token 和 openid  
	@RequestMapping("/codeLogin")
	public SaResult codeLogin(String code) throws JsonProcessingException {
		// 调用Server端接口，获取 Access-Token 以及其他信息
		String str = OkHttps.sync(serverUrl + "/17/oauth2/token")
				.addBodyPara("grant_type", "authorization_code")
				.addBodyPara("code", code)
				.addBodyPara("client_id", clientId)
				.addBodyPara("client_secret", clientSecret)
				.addBodyPara("scope", "openid,userinfo,oidc")
				.post()
				.getBody()
				.toString();
		System.out.println(str);
		JSONObject entries = JSONUtil.parseObj(str);
		System.out.println("返回结果: " + entries);



		SaResult accessToken = getUserinfo(entries.getStr("access_token"));
		System.out.println("<UNK>: " + accessToken);


		// code不等于200  代表请求失败 
		if(entries.getInt("code") != 200) {
			return SaResult.error(entries.getStr("msg"));
		}
		// 根据openid获取其对应的userId
		StpUtil.login(entries.getStr("userId"));
		entries.set("uid", StpUtil.getLoginIdDefaultNull());
		return SaResult.data(entries);
	}
	
	// 根据 Refresh-Token 去刷新 Access-Token 
	@RequestMapping("/refresh")
	public SaResult refresh(String refreshToken) throws JsonProcessingException {
		// 调用Server端接口，通过 Refresh-Token 刷新出一个新的 Access-Token 
		String str = OkHttps.sync(serverUrl + "/17/oauth2/refresh")
				.addBodyPara("grant_type", "refresh_token")
				.addBodyPara("client_id", clientId)
				.addBodyPara("client_secret", clientSecret)
				.addBodyPara("refresh_token", refreshToken)
				.post()
				.getBody()
				.toString();

		JSONObject so = JSONUtil.parseObj(str);

		System.out.println("返回结果: " + so);

		// code不等于200  代表请求失败 
		if(so.getInt("code") != 200) {
			return SaResult.error(so.getStr("msg"));
		}

		// 返回相关参数
		return SaResult.data(so);
	}
	
	// 模式三：密码式-授权登录
	@RequestMapping("/passwordLogin")
	public SaResult passwordLogin(String username, String password) throws JsonProcessingException {
		// 模式三：密码式-授权登录
		String str = OkHttps.sync(serverUrl + "/17/oauth2/token")
				.addBodyPara("grant_type", "password")
				.addBodyPara("client_id", clientId)
				.addBodyPara("client_secret", clientSecret)
				.addBodyPara("username", username)
				.addBodyPara("password", password)
				.addBodyPara("scope", "openid,userinfo,oidc")
				.post()
				.getBody()
				.toString();
		JSONObject so = JSONUtil.parseObj(str);
		System.out.println("返回结果: " + so);

		// code不等于200  代表请求失败 
		if(so.getInt("code") != 200) {
			return SaResult.error(so.getStr("msg"));
		}

		// 返回相关参数
		StpUtil.login(so.getStr("openid"));
		return SaResult.data(so);
	}
	
	// 模式四：获取应用的 Client-Token 
	@RequestMapping("/clientToken")
	public SaResult clientToken() throws JsonProcessingException {
		// 调用Server端接口
		String str = OkHttps.sync(serverUrl + "/17/oauth2/client_token")
				.addBodyPara("grant_type", "client_credentials")
				.addBodyPara("client_id", clientId)
				.addBodyPara("client_secret", clientSecret)
				.addBodyPara("scope", "openid,userinfo,oidc")
				.post()
				.getBody()
				.toString();
		JSONObject so = JSONUtil.parseObj(str);

		System.out.println("返回结果: " + so);

		// code不等于200  代表请求失败 
		if(so.getInt("code") != 200) {
			return SaResult.error(so.getStr("msg"));
		}

		// 返回相关参数
		return SaResult.data(so);
	}
	
	// 注销登录 
	@RequestMapping("/logout")
	public SaResult logout() {
		StpUtil.logout();
		return SaResult.ok();
	}

	// 根据 Access-Token 置换相关的资源: 获取账号昵称、头像、性别等信息 
	@RequestMapping("/getUserinfo")
	public static SaResult getUserinfo(String accessToken) throws JsonProcessingException {
		// 调用Server端接口，查询开放的资源 
		String str = OkHttps.sync(serverUrl + "/17/oauth2/userinfo")
				.addBodyPara("access_token", accessToken)
				.post()
				.getBody()
				.toString();
		JSONObject so = JSONUtil.parseObj(str);

		System.out.println("返回结果: " + so);

		// code不等于200  代表请求失败 
		if(so.getInt("code") != 200) {
			return SaResult.error(so.getStr("msg"));
		}

		// 返回相关参数 (data=获取到的资源 )
		return SaResult.data(so);
	}


	public static void main(String[] args) throws JsonProcessingException {

		SaResult userinfo = getUserinfo("6eVeZ4EOgbj1oby5hI6jvnUwj6i1odcm5xn8uypNXLL8xluDD4nNl0Hkgs9s");
		System.out.println(userinfo);
	}

}
